unit frm_MainForm;

interface

uses
  // Delphi units
  Windows,
  ShellAPI,
  Messages,
  SysUtils,
  StrUtils,
  Variants,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls,
  ExtCtrls,
  ComCtrls,
  Menus,
  Tabs,
  Buttons,
  DB,
  Grids,
  DBGrids,
  // My units
  unit_AppSettings,
  unit_SettingsConsts,
  unit_fmLogFile,
  unit_GenesisLocalRepository,
  unit_CSVFile,
//  data_MainDataModule,
  // 3rd party components
  MD5,
  unit_MD5Misc,
  cySearchFiles,
  cyCopyFiles, cyBaseLed, cyLed, cyDBLed, cyFieldLink, cyBaseMeasure,
  cyCustomGauge, cySimpleGauge;

type
  TfrmMain = class(TForm)
    bvlDelimiter: TBevel;
    mnuMainMenu: TMainMenu;
    File1: TMenuItem;
    Settings1: TMenuItem;
    Help1: TMenuItem;
    Exit1: TMenuItem;
    pnlTabCaption: TPanel;
    pnlTabsPanel: TPanel;
    pnlTabPages: TPanel;
    pgcTasks: TPageControl;
    tabDatabase: TTabSheet;
    dgrMemoryTable: TDBGrid;
    tabCheckRepositoryFiles: TTabSheet;
    grpMissedFilesCheckSettings: TGroupBox;
    chkCheckMD5Hash: TCheckBox;
    chkCheckFileSize: TCheckBox;
    pnlCommands: TPanel;
    btnAnalizeRepository: TButton;
    tabDataImport: TTabSheet;
    tabDataExport: TTabSheet;
    tabStats: TTabSheet;
    tabSettings: TTabSheet;
    tabLogs: TTabSheet;
    pnlTabSelector: TPanel;
    btnDBSettings: TBitBtn;
    btnCheckMissedFiles: TBitBtn;
    btnImportToGenesis: TBitBtn;
    bvl1: TBevel;
    bvl2: TBevel;
    pnlCommandPanel: TPanel;
    bvl3: TBevel;
    btnCreateDBfromCSV: TBitBtn;
    edtGenesisCSVFile: TEdit;
    btnSelectCSVFile: TButton;
    btnSelectLocalDBDumpFile: TButton;
    edtLocalDBDumpFile: TEdit;
    btnLoadLocalDBFromDump: TBitBtn;
    chkAutoSaveDBDump: TCheckBox;
    chkAutoLoadDBDump: TCheckBox;
    bvl4: TBevel;
    btnOpenCloseDB: TBitBtn;
    lblDBState: TLabel;
    btnSaveDBToDump: TBitBtn;
    btnShowTable: TBitBtn;
    lblTableViewState: TLabel;
    tabCheckExtraFiles: TTabSheet;
    chkCheckCRC32: TCheckBox;
    grpCheckStatistics: TGroupBox;
    grpExtraFilesCheckSettings: TGroupBox;
    lblCheckStartID: TLabel;
    edtCheckStartID: TEdit;
    udCheckStartID: TUpDown;
    udCheckFinishID: TUpDown;
    edtCheckFinishID: TEdit;
    lblCheckLastID: TLabel;
    chkCheckMissedFiles: TCheckBox;
    chkCheckExtraFiles: TCheckBox;
    chkCheckOutdatedFiles: TCheckBox;
    chkCheckMisplacedFiles: TCheckBox;
    chkMoveMisplacedFiles: TCheckBox;
    chkMoveOutdatedFiles: TCheckBox;
    lblFilesProcessedStat: TLabel;
    lblGenesisID: TLabel;
    edtGenesisID: TEdit;
    edtFilesProcessedStat: TEdit;
    edtFileFoundStat: TEdit;
    lblFilesFoundStat: TLabel;
    lblFilesMissedStat: TLabel;
    edtFilesMissedStat: TEdit;
    edtCRC32ErrorStat: TEdit;
    lblCRC32ErrorStat: TLabel;
    lblMD5ErrorStat: TLabel;
    edtMD5ErrorStat: TEdit;
    lblFilesizeErrorStat: TLabel;
    edtFileSizeErrorStat: TEdit;
    edtExtraFilesStat: TEdit;
    lblExtraFilesStat: TLabel;
    chkShowWorkTimeMsg: TCheckBox;
    btnLogFileFoundShow: TButton;
    btnLogFileSizeErrorShow: TButton;
    btnLogFileMissedShow: TButton;
    btnLogExtraFilesShow: TButton;
    btnLogCRC32ErrorShow: TButton;
    btnLogMD5ErrorShow: TButton;
    btnLogFileURLsShow: TButton;
    procedure btnLogFileFoundShowClick(Sender: TObject);
    procedure btnAnalizeRepositoryClick(Sender: TObject);
    procedure btnCheckMissedFilesClick(Sender: TObject);
    procedure btnDBSettingsClick(Sender: TObject);
    procedure btnImportToGenesisClick(Sender: TObject);
    procedure btnLoadCSVFileClick(Sender: TObject);
    procedure btnCreateDBfromCSVClick(Sender: TObject);
    procedure btnLoadLocalDBFromDumpClick(Sender: TObject);
    procedure btnLogCRC32ErrorShowClick(Sender: TObject);
    procedure btnLogExtraFilesShowClick(Sender: TObject);
    procedure btnLogFileMissedShowClick(Sender: TObject);
    procedure btnLogFileSizeErrorShowClick(Sender: TObject);
    procedure btnLogFileURLsShowClick(Sender: TObject);
    procedure btnLogMD5ErrorShowClick(Sender: TObject);
    procedure btnOpenCloseDBClick(Sender: TObject);
    procedure btnSaveDBToDumpClick(Sender: TObject);
    procedure btnSaveTableToFileClick(Sender: TObject);
    procedure btnSelectCSVFileClick(Sender: TObject);
    procedure btnSelectLocalDBDumpFileClick(Sender: TObject);
    procedure btnShowTableClick(Sender: TObject);
    procedure chkAutoLoadDBDumpClick(Sender: TObject);
    procedure chkAutoSaveDBDumpClick(Sender: TObject);
    procedure chkCheckCRC32Click(Sender: TObject);
    procedure chkCheckExtraFilesClick(Sender: TObject);
    procedure chkCheckFileSizeClick(Sender: TObject);
    procedure chkCheckMD5HashClick(Sender: TObject);
    procedure chkCheckMisplacedFilesClick(Sender: TObject);
    procedure chkCheckMissedFilesClick(Sender: TObject);
    procedure chkCheckOutdatedFilesClick(Sender: TObject);
    procedure chkMoveMisplacedFilesClick(Sender: TObject);
    procedure chkMoveOutdatedFilesClick(Sender: TObject);
    procedure edtCheckFinishIDChange(Sender: TObject);
    procedure edtCheckStartIDChange(Sender: TObject);
    procedure edtGenesisCSVFileChange(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure jvtrtl1RepaintRequest(Sender: TObject);
    procedure pgc1Change(Sender: TObject);
    procedure pgcTasksChange(Sender: TObject);
    procedure pnlTabCaptionClick(Sender: TObject);
    procedure pnlTabSelectorClick(Sender: TObject);
    procedure Settings1Click(Sender: TObject);
    procedure udCheckFinishIDChangingEx(Sender: TObject; var AllowChange: Boolean;
        NewValue: SmallInt; Direction: TUpDownDirection);
    procedure udCheckStartIDChangingEx(Sender: TObject; var AllowChange: Boolean;
        NewValue: SmallInt; Direction: TUpDownDirection);
  private
    { Private declarations }
    FAppSettings :TAppSettings;
    FGenesisLocal: TGenesisLocalRepository;
    //
    // Result stringlists variables
    //
    FProcessedFilesList: TStringList;
    FCurrentGenesisID: Integer;
    FGenesisProcessedFiles: Integer;
    FCheckErrorsCount: Integer;
    //
    FGenesisExistFilesCount: Integer;
    FGenesisMissedFilesCount: Integer;
    FGenesisOutdatedFilesCount: Integer;
    FGenesisExtraFilesCount: Integer;
    //
    FGenesisMD5ErrorCount: integer;
    FGenesisCRC32ErrorCount: integer;
    FGenesisFileSizeErrorCount: integer;
    //
    // process flag variables
    //
    FProcessing: Boolean;
    FInitialized: Boolean;
    FCSVFile: TCSVFile;
    //
    // Log files variables
    //
    FLogExistFiles: TfmLogFile;
    FLogMissedFiles: TfmLogFile;
    FLogErrorFileSize: TfmLogFile;
    FLogErrorMD5: TfmLogFile;
    FLogMissedFilesURL: TfmLogFile;
    //
    FLogExtraFiles: TfmLogFile;
    FLogErrorID: TfmLogFile;
    FLogRepositoryNotSet: TfmLogFile;
    FLogOutdatedFiles: TfmLogFile;
  protected
    function CheckExtraFiles(const FirstID: Integer = 0; const LastID: Integer =
        0): Boolean;
    function CheckLocalFiles(const FirstID: Integer = 0; const LastID: Integer =
        0): Boolean;
    function CheckRepositoryFile(const FileIndex: integer; const CheckFileSize:
        Boolean = True; const CheckMD5: Boolean = False): Boolean;
    //
    procedure CreateLogFiles;
    procedure FreeLogFiles;
    function UpdateLogFiles(const FileState: TFileState;
        const GenesisFile: TGenesisRecord): Boolean;

    //
    function GetLocalRepositoryDir(const GenesisID: Integer): AnsiString;
    function GetGenesisFileURL(const GenesisFile: TGenesisRecord): AnsiString;
    function GetServerTemplateURL(const GenesisID: Integer): AnsiString;
    function GetStartFileIndex(const GenesisID: Integer): Integer;
    //
    function LoadGenesisFileList(const FileName: AnsiString): Boolean;
    function LoadGenesisData(const GenesisFileList: AnsiString): Boolean;
    procedure LoadRepositoriesData(var LocalRepository: TGenesisLocalRepository);
    function ParseRecord(const InputString: AnsiString; const FieldDelimiter:
        AnsiChar; const UnQuoteStr: Boolean; var SL: TStringList): Integer;
    //
    procedure SetControlStates;
    procedure SetControlState(Control: TWinControl; const State: Boolean);
    procedure SetLocalDBTabControlsState;
    procedure SetCheckRepositoryFilesTabControlsState;
    procedure ShowProgressStatistics(const Visible: Boolean);
    //
    // Load|save settings functions
    //
    procedure LoadAppSettings;
    procedure SaveAppSettings;
    //
    procedure LoadAppCheckSettings;
    procedure SaveAppCheckSettings;
    //
    procedure LoadAppLogSettings;
    procedure SaveAppLogSettings;
    //
    procedure LoadAppLocalDBSettings;
    procedure SaveAppLocalDBSettings;
  {---------------------public properties and functions------------------------}
  public

    procedure ValidateFile(Sender: TObject;
        ValidMaskInclude, ValidMaskExclude, ValidAttributes: boolean;
        var Accept: boolean);
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

uses
  frm_Settings,
  frm_SplashScreen,
  Res_interface_eng;

{$R *.dfm}

procedure TfrmMain.btnLogFileFoundShowClick(Sender: TObject);
var
  nCounter: Integer;
  cLogFile: AnsiString;
  bLogView: Boolean;
begin
  nCounter := StrToIntDef(edtFileFoundStat.Text,0);
  cLogFile := Settings.LogFileExistFiles;
  bLogView := (nCounter > 0) and FileExists(cLogFile);
  if bLogView then begin
    ShellExecute(0,'open', PChar(cLogFile), '', '', SW_NORMAL);
//    WinExec(PChar(QuotedStr(Settings.LogFileExistFiles)), SW_SHOW);
  end;
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.btnAnalizeRepositoryClick
//   Start genesis repository analisys
// Parameters:
//   None
// Result:
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.btnAnalizeRepositoryClick(Sender: TObject);
var
  //
  // id variables
  //
  nFirstID: Integer;
  nLastID: Integer;
  //
  // Flag variables
  //
  xFileChecks: TCheckState;
  //
  // Working time variables
  //
  dtStartCheck: TDateTime;
  dtEndCheck: TDateTime;
  dtWorkTime: TDateTime;
begin
  FProcessing := True;
  SetControlStates;
  //
  dtStartCheck := Now;
  //
  // Initialize check flag variables
  //
  xFileChecks := Settings.LocalFilesChecks;
  FGenesisLocal.StartCheck;
  FGenesisLocal.FileChecks := xFileChecks;
  //
  // Initialize file's counter variables
  //
  FGenesisExistFilesCount := 0;
  FGenesisProcessedFiles := 0;
  FGenesisMissedFilesCount := 0;
  FGenesisExtraFilesCount := 0;
  FGenesisMD5ErrorCount := 0;
  FGenesisCRC32ErrorCount := 0;
  FGenesisFileSizeErrorCount := 0;
  //
  // Process all files in cycle
  //
  nFirstID := Settings.CheckStartID;
  nLastID := Settings.CheckFinishID;
  //
  // Create and initialize log files variables
  //
  CreateLogFiles;
  //
  // Check local repository for extra and missed files
  //
  if Settings.ProcessLocalFiles then CheckLocalFiles(nFirstID, nLastID);
  if Settings.ProcessExtraFiles then CheckExtraFiles(nFirstID, nLastID);
  //
  // Free log files variables
  //
  FreeLogFiles;
  //
  // Get work time and show information message
  //
  dtWorkTime := Now - dtStartCheck;
  if chkShowWorkTimeMsg.Checked then
    ShowMessage('Work time is ' + TimeToStr(dtWorkTime));
  //
  // Set file processing state
  //
  FGenesisLocal.EndCheck;
  FProcessing := False;
  SetControlStates;
end;

procedure TfrmMain.btnCheckMissedFilesClick(Sender: TObject);
begin
  pgcTasks.ActivePageIndex :=(Sender as TControl).Tag;
  pnlTabCaption.Caption := pgcTasks.ActivePage.Caption;
//  (Sender as TBitBtn).Font.Style := [fsBold];
end;

procedure TfrmMain.btnDBSettingsClick(Sender: TObject);
begin
  pgcTasks.ActivePageIndex := (Sender as TControl).Tag;
  pnlTabCaption.Caption := pgcTasks.ActivePage.Caption;
end;

procedure TfrmMain.btnImportToGenesisClick(Sender: TObject);
begin
  pgcTasks.ActivePageIndex := (Sender as TControl).Tag;
  pnlTabCaption.Caption := pgcTasks.ActivePage.Caption;  
end;

procedure TfrmMain.btnLoadCSVFileClick(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.btnLoadCSVFileClick default body inserted
end;

procedure TfrmMain.btnCreateDBfromCSVClick(Sender: TObject);
begin
  FProcessing := True;
  SetControlStates;
  try
    frmMain.Cursor := crHourGlass;
    LoadGenesisData(Settings.GenesisCSVFile);
    frmMain.Cursor := crDefault;
  finally
    FProcessing := False;
    SetControlStates;
  end;
end;

procedure TfrmMain.btnLoadLocalDBFromDumpClick(Sender: TObject);
begin
  FProcessing := True;
  SetControlStates;
  FGenesisLocal.LoadDataFromDump(edtLocalDBDumpFile.Text);
  //
  FProcessing := False;
  SetControlStates;
end;

procedure TfrmMain.btnLogCRC32ErrorShowClick(Sender: TObject);
var
  nCounter: Integer;
  cLogFile: AnsiString;
  bLogView: Boolean;
begin
  nCounter := StrToIntDef(edtCRC32ErrorStat.Text,0);
//  cLogFile := Settings.LogFileErrorCRC32;
  bLogView := (nCounter > 0) and FileExists(cLogFile);
  if bLogView then begin
//    ShellExecute(0,'open', PChar(cLogFile), '', '', SW_NORMAL);
  end;
end;
procedure TfrmMain.btnLogExtraFilesShowClick(Sender: TObject);
var
  nCounter: Integer;
  cLogFile: AnsiString;
  bLogView: Boolean;
begin
  nCounter := StrToIntDef(edtExtraFilesStat.Text,0);
  cLogFile := Settings.LogFileExtraFiles;
  bLogView := (nCounter > 0) and FileExists(cLogFile);
  if bLogView then begin
    ShellExecute(0,'open', PChar(cLogFile), '', '', SW_NORMAL);
//    WinExec(PChar(QuotedStr(Settings.LogFileExistFiles)), SW_SHOW);
  end;
end;
procedure TfrmMain.btnLogFileMissedShowClick(Sender: TObject);
var
  nCounter: Integer;
  cLogFile: AnsiString;
  bLogView: Boolean;
begin
  nCounter := StrToIntDef(edtFilesMissedStat.Text,0);
  cLogFile := Settings.LogFileMissedFiles;
  bLogView := (nCounter > 0) and FileExists(cLogFile);
  if bLogView then begin
    ShellExecute(0,'open', PChar(cLogFile), '', '', SW_NORMAL);
//    WinExec(PChar(QuotedStr(Settings.LogFileExistFiles)), SW_SHOW);
  end;
end;

procedure TfrmMain.btnLogFileSizeErrorShowClick(Sender: TObject);
var
  nCounter: Integer;
  cLogFile: AnsiString;
  bLogView: Boolean;
begin
  nCounter := StrToIntDef(edtFileSizeErrorStat.Text,0);
  cLogFile := Settings.LogFileErrorFileSize;
  bLogView := (nCounter > 0) and FileExists(cLogFile);
  if bLogView then begin
    ShellExecute(0,'open', PChar(cLogFile), '', '', SW_NORMAL);
//    WinExec(PChar(QuotedStr(Settings.LogFileExistFiles)), SW_SHOW);
  end;
end;

procedure TfrmMain.btnLogFileURLsShowClick(Sender: TObject);
var
  nCounter: Integer;
  cLogFile: AnsiString;
  bLogView: Boolean;
begin
  nCounter := StrToIntDef(edtFilesMissedStat.Text,0);
  cLogFile := Settings.LogFileMissedFilesURL;
  bLogView := (nCounter > 0) and FileExists(cLogFile);
  if bLogView then begin
    ShellExecute(0,'open', PChar(cLogFile), '', '', SW_NORMAL);
//    WinExec(PChar(QuotedStr(Settings.LogFileExistFiles)), SW_SHOW);
  end;
end;

procedure TfrmMain.btnLogMD5ErrorShowClick(Sender: TObject);
var
  nCounter: Integer;
  cLogFile: AnsiString;
  bLogView: Boolean;
begin
  nCounter := StrToIntDef(edtMD5ErrorStat.Text,0);
  cLogFile := Settings.LogFileErrorMD5;
  bLogView := (nCounter > 0) and FileExists(cLogFile);
  if bLogView then begin
    ShellExecute(0,'open', PChar(cLogFile), '', '', SW_NORMAL);
//    WinExec(PChar(QuotedStr(Settings.LogFileExistFiles)), SW_SHOW);
  end;
end;

procedure TfrmMain.btnOpenCloseDBClick(Sender: TObject);
begin
  FGenesisLocal.TableActive := not FGenesisLocal.TableActive;
  //
  SetControlStates;
end;

procedure TfrmMain.btnSaveDBToDumpClick(Sender: TObject);
var
  cFileName: AnsiString;
  bSaveDump: Boolean;
begin
  cFileName := Settings.LocalDBDumpFile;
  if Settings.SelectFile(cFileName) then begin
    //
    // Confirm file replacement, if file already exists
    //
    if FileExists(cFileName) then begin
      bSaveDump := MessageBox(0, PChar('File' + cFileName + 'already exists.'
        + #10 + #13 + 'Replace dump?'),'Warning', MB_YESNO) = IDOK;
    end
    else
      bSaveDump := True;
    //
    // Save current DB to dump file
    //
    if bSaveDump then begin
      //
      // Refresh gui elements state
      //
      FProcessing := True;
      SetControlStates;
      //
      // Force file directory creation
      //
      ForceDirectories(ExtractFileDir(cFileName));
      //
      // Save current DB to dump file and update current db dump filename
      //
      if FGenesisLocal.SaveDataToDump(cFileName) then
        Settings.LocalDBDumpFile := cFileName;
    end;
  end;
  //
  FProcessing := False;
  SetControlStates;
end;
//
procedure TfrmMain.btnSaveTableToFileClick(Sender: TObject);
begin
 // TODO -cMM: TfrmMain.btnSaveTableToFileClick default body inserted
end;
//
procedure TfrmMain.btnSelectCSVFileClick(Sender: TObject);
var
  cFileName: AnsiString;
begin
 if Settings.SelectFile(cFileName) then begin
    edtGenesisCSVFile.Text := cFileName;
    Settings.GenesisCSVFile := cFileName;
  end;
  SetControlStates;
end;
//
procedure TfrmMain.btnSelectLocalDBDumpFileClick(Sender: TObject);
var
  cFileName: AnsiString;
begin
 if Settings.SelectFile(cFileName) then begin
    edtLocalDBDumpFile.Text := cFileName;
    Settings.LocalDBDumpFile := cFileName;
  end;
  SetControlStates;
end;
//
procedure TfrmMain.btnShowTableClick(Sender: TObject);
begin
  dgrMemoryTable.DataSource := FGenesisLocal.DataSource;
  dgrMemoryTable.DataSource.Enabled := not dgrMemoryTable.DataSource.Enabled;
  //
  SetControlStates;
end;

//============================================================================
//
//TProcOnValidateFileEvent = procedure (Sender: TObject; ValidMaskInclude, ValidMaskExclude, ValidAttributes: boolean; var Accept: boolean) of object;
//
procedure TfrmMain.ValidateFile(Sender: TObject;
  ValidMaskInclude, ValidMaskExclude, ValidAttributes: boolean;
  var Accept: boolean);
const
  FILE_NOT_FOUND_ID = -1;
var
  xFile: TcySearchFiles;
  xGenesisFile: TGenesisRecord;
  xFileState: TFileState;
  cFileName: AnsiString;
  nFileID: integer;
  //
  // Flag variables
  //
  bIsExtraFile: Boolean;
  bFileProcessed: Boolean;
begin
  if Accept    // Accept only files with correct mask, date, size etc
  then begin
    xFile := Sender as TcySearchFiles;
    xFileState := [];
    //
    // Get founded file absolute filename
    //
    cFileName := xFile.CurrentDirectory + xFile.CurrentFileName;
    //
    // Get genesis local repository file id from specified filename.
    //   If record don't found, FILE_NOT_FOUND_ID (-1) is retourned
    //
    xGenesisFile.Clear;
    xGenesisFile.FileName := xFile.CurrentFileName;
    xGenesisFile.RootDir := xFile.CurrentDirectory;
    //
    bFileProcessed :=
      FGenesisLocal.CheckFile(xGenesisFile.FullName, xFileState, nFileID);
    if not bFileProcessed then begin
      Inc(FCheckErrorsCount);
    end
    else begin
      //
      // Check if file is already processed (return ID = -100).
      //   If so, skip log processing
      //
      if nFileID = -100 then begin
        Exit;
      end;
      if nFileID = -1 then begin

      end;
    end;
    UpdateLogFiles(xFileState, xGenesisFile);
  end
  else begin

  end;
  //
  // Let user pause/resume and abort :
  //
  Application.ProcessMessages;
end;
//============================================================================

//------------------------------------------------------------------------------
// function TfrmMain.CheckExtraFiles
//   Check local repository for extra files (specified id range only)
// Parameters:
//   const FirstID : Integer - first range id (if zero, assign minimum id)
//   const LastID : Integer  - last range id (if zero, assign maximum id)
// Result: Boolean
//   True, if operation succeed, False otherwise
//------------------------------------------------------------------------------
function TfrmMain.CheckExtraFiles(const FirstID: Integer = 0; const LastID:
    Integer = 0): Boolean;
var
  //
  // Processed files list variables
  //
  slDirectories: TStringList;
  slFilesList: TStringList;
  //
  i:Integer;
  nDirIndex: Integer;
  cCurrentDir: AnsiString;
  cFilesExclude: AnsiString;
  cFilesInclude: AnsiString;
  //
  //
  //
  xFileSearch: TcySearchFiles;
  xColl: TCollection;
  //
  // Flag variables
  //
  bFileProcessed: Boolean;
  xCurrentRecord: TGenesisRecord;
  xFileState: TFileState;
  xFileChecks: TCheckState;
begin
  try
    //
    // Generate files check list
    //
    slFilesList := TStringList.Create;
    slFilesList.Clear;
    //
    slDirectories := TStringList.Create;
    slDirectories.Duplicates := dupIgnore;
    slDirectories.Sorted := True;
    slDirectories.Clear;
    //
    //
    // Get all repositories directories in cycle from database
    //
    { TODO -oMichel -c :  Remake getting directories listing to sql db request 05.11.2010 6:47:39 }
    for i := FirstID to LastID do begin
      xCurrentRecord := FGenesisLocal.Files[i];
      if xCurrentRecord.RootDir = EmptyStr then
        Continue;
      cCurrentDir := ExtractFileDir(xCurrentRecord.FullName);
      Assert(cCurrentDir <> EmptyStr, 'CheckExtraFiles - empty folder error');
      slDirectories.Add(cCurrentDir);
    end;
    //
    // Check for extra files in specified genesis id range
    //
    xFileSearch := TcySearchFiles.Create(nil);
    xFileSearch.MaskInclude.DelimitedText := '';
    xFileSearch.MaskExclude.DelimitedText := ''; //'*.!ut';
    xFileSearch.SubDirectories := True;
    //
    // Assign validate file process procedure
    //
    xFileSearch.OnValidateFile := ValidateFile;
    //
    // Search all files in specified directory and test it for validity
    //
    for nDirIndex := 0 to slDirectories.Count - 1 do begin
      xFileSearch.FromPath := slDirectories[nDirIndex];
      xFileSearch.Execute;
      ShowProgressStatistics(True);
    end;
  finally
    FreeAndNil(slDirectories);
    FreeAndNil(slFilesList);
    FreeAndNil(xFileSearch);
  end;
end;
//------------------------------------------------------------------------------
// function TfrmMain.CheckLocalFiles
//   Check local repository for missed files
// Parameters:
// -
// Result: None
//------------------------------------------------------------------------------
function TfrmMain.CheckLocalFiles(const FirstID: Integer = 0; const LastID:
    Integer = 0): Boolean;
const
  BAD_ID = -1;
var
  //
  // temporary index variable
  //
  nFileIndex: integer;
  nStartIndex: Integer;
  nEndIndex: Integer;
  //
  // Flag variables
  //
  bFileProcessed: Boolean;
  bFileSkipped: Boolean;
  xCurrentRecord: TGenesisRecord;
  nFileID: Integer;
  xFileState: TFileState;
  xFileChecks: TCheckState;
begin
  try
    //
    // Process all local repository files in cycle
    //
    nStartIndex := Settings.CheckStartID;
    nEndIndex := Settings.CheckFinishID;
    //
    ShowProgressStatistics(True);
    for nFileIndex := nStartIndex to nEndIndex do begin
      xCurrentRecord := FGenesisLocal.Files[nFileIndex];
      bFileProcessed :=
        FGenesisLocal.CheckFile(xCurrentRecord.FullName, xFileState, nFileID);
      FCurrentGenesisID := xCurrentRecord.ID;
      //
      // Update log files and class counters variables
      //
      bFileSkipped := nFileID = -100;
      if bFileProcessed then begin
        if not bFileSkipped then
          UpdateLogFiles(xFileState, xCurrentRecord)
      end
      else
        Inc(FCheckErrorsCount);
      ShowProgressStatistics(True);
    end;
  finally

  end;
end;
//------------------------------------------------------------------------------
// function TfrmMain.CheckRepositoryFile
//   Check if file is present in repository and his filesize is correct
// Parameters:
//   const FileIndex: integer - index of file in internal archive variables
//   const CheckMD5: boolean - additionnally check MD5 hash
// Result:
//   None
//------------------------------------------------------------------------------
function TfrmMain.CheckRepositoryFile(const FileIndex: integer;
  const CheckFileSize: Boolean = True; const CheckMD5: Boolean = False): Boolean;
//const
//  BUF_SIZE = 65536;
var
  cRepositoryDir: AnsiString;
  cGenesisFileName: AnsiString;
  fsGenesisFile: TFileStream;
  //
  // MD5 calculation variables
  //
  cMD5String: AnsiString;
  xMD5Digest: TMD5Digest;
  //
  // File check results
  //
  bFileExists: Boolean;
  bCorrectFileSize: Boolean;
  bCorrectMD5: Boolean;
  Buf: PChar;
begin
  //
  // Get local repository directory
  //
  cRepositoryDir :=
    GetLocalRepositoryDir(FGenesisLocal.Files[FileIndex].ID);
  if cRepositoryDir = '' then begin
    Result := False;
    Exit;
  end;
  //
  // Get current file's full filename
  //
  cGenesisFileName :=
    cRepositoryDir + FGenesisLocal.Files[FileIndex].FileName;
  //
  // Check if file exists. Exit function, if result is false.
  //
  bFileExists := FileExists(cGenesisFileName);
  if not bFileExists then begin
    Result := False;
    Exit;
  end;
  //
  // if supplementairy check don't set, set result to True and exit function
  //
  if (not CheckFileSize) and (not CheckMD5) then begin
    Result := True;
    Exit;
  end;
  //
  // Check if file size is correct. Exit function, if result is false
  //
  try
    fsGenesisFile := TFileStream.Create(cGenesisFileName, fmOpenRead + fmShareDenyNone);
    if CheckFileSize then begin
      bCorrectFileSize :=
        fsGenesisFile.Size = FGenesisLocal.Files[FileIndex].FileSize;
      if not bCorrectFileSize then begin
        Result := False;
        Exit;
      end;
    end;
    //
    // Check file's MD5 hash summe
    //
    if CheckMD5 then begin
      { TODO -oAdministrator -c :  Test speed of md5 calcul 03.04.2010 18:20:45 }
      //
      // Start test module
      //
      if True then begin
        xMD5Digest := MD5Stream(fsGenesisFile);
        cMD5String := LowerCase(MD5DigestToStr(xMD5Digest));
      end
      else begin
        cMD5String := LowerCase(md5sum(fsGenesisFile, nil));
      end;
      //
      // End test module
      //
      bCorrectMD5 := cMD5String = FGenesisLocal.Files[FileIndex].MD5;
      if not bCorrectMD5 then begin
        Result := False;
        Exit;
      end;
    end;
    //
    // if errors don't occured, sef Result to True and exit function
    //
    Result := True;
  finally
    FreeAndNil(fsGenesisFile);
  end;
end;
//
procedure TfrmMain.chkAutoLoadDBDumpClick(Sender: TObject);
begin
  Settings.AutoLoadLocalDBDump := chkAutoLoadDBDump.Checked;
  SetControlStates;
end;
//
procedure TfrmMain.chkAutoSaveDBDumpClick(Sender: TObject);
begin
  Settings.AutoSaveLocalDBDump := chkAutoSaveDBDump.Checked;
  SetControlStates;
end;
//
procedure TfrmMain.chkCheckCRC32Click(Sender: TObject);
begin
  if chkCheckCRC32.Checked then
    Settings.LocalFilesChecks := Settings.LocalFilesChecks + [cstCRC32]
  else
    Settings.LocalFilesChecks := Settings.LocalFilesChecks - [cstCRC32];
  //
  SetControlStates;
end;
//
procedure TfrmMain.chkCheckExtraFilesClick(Sender: TObject);
begin
  Settings.ProcessExtraFiles := chkCheckExtraFiles.Checked;
  SetControlStates;
end;
//
procedure TfrmMain.chkCheckFileSizeClick(Sender: TObject);
begin
  if chkCheckFileSize.Checked then
    Settings.LocalFilesChecks := Settings.LocalFilesChecks + [cstFileSize]
  else
    Settings.LocalFilesChecks := Settings.LocalFilesChecks - [cstFileSize];
  //
  SetControlStates;
end;
//
procedure TfrmMain.chkCheckMD5HashClick(Sender: TObject);
begin
  if chkCheckMD5Hash.Checked then
    Settings.LocalFilesChecks := Settings.LocalFilesChecks + [cstMD5]
  else
    Settings.LocalFilesChecks := Settings.LocalFilesChecks - [cstMD5];
  //
  SetControlStates;
end;

procedure TfrmMain.chkCheckMisplacedFilesClick(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.chkCheckMisplacedFilesClick default body inserted
end;

procedure TfrmMain.chkCheckMissedFilesClick(Sender: TObject);
begin
  Settings.ProcessLocalFiles := chkCheckMissedFiles.Checked;
  SetControlStates;
end;

procedure TfrmMain.chkCheckOutdatedFilesClick(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.chkCheckOutdatedFilesClick default body inserted
end;

procedure TfrmMain.chkMoveMisplacedFilesClick(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.chkMoveMisplacedFilesClick default body inserted
end;

procedure TfrmMain.chkMoveOutdatedFilesClick(Sender: TObject);
begin
end;

//------------------------------------------------------------------------------
// procedure TfrmMain.CreateLogFiles
//   Create log files on program start
// Parameters:
// -
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.CreateLogFiles;
var
  cLogFileName: AnsiString;
begin
  //
  // Create log file for records with uncorrect files' ID
  //
  if Settings.LogCreateErrorID then begin
    FLogErrorID := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileErrorID, Settings.AppDir);
    FLogErrorID.CreateFile(cLogFileName);
  end;
  //
  // Create log file for exist files
  //
  if Settings.LogCreateExistFiles then begin
    FLogExistFiles := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileExistFiles, Settings.AppDir);
    with FLogExistFiles do begin
      CreateFile(cLogFileName);
      WriteToLog('CheckRepository log file', rtComment);
      WriteToLog('Files present in repository', rtComment);
      WriteToLog(DateTimeToStr(Now), rtComment);
    end;
  end;
  //
  // Create log file for outdated files
  //
  if Settings.LogCreateOutdatedFiles then begin
    FLogOutdatedFiles := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileOutdatedFiles, Settings.AppDir);
    FLogOutdatedFiles.CreateFile(cLogFileName);
  end;
  //
  // Create log file for extra files
  //
  if Settings.LogCreateExtraFiles then begin
    FLogExtraFiles := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileExtraFiles, Settings.AppDir);
    with FLogExtraFiles do begin
      CreateFile(cLogFileName);
      WriteToLog('CheckRepository log file', rtComment);
      WriteToLog('Extra files present in repository', rtComment);
      WriteToLog(DateTimeToStr(Now), rtComment);
    end;
  end;
  //
  // Create log files for missed files
  //
  if Settings.LogCreateMissedFiles then begin
    FLogMissedFiles := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileMissedFiles, Settings.AppDir);
    FLogMissedFiles.CreateFile(cLogFileName);
  end;
  //
  if Settings.LogCreateMissedFilesURL then begin
    FLogMissedFilesURL := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileMissedFilesURL, Settings.AppDir);
    FLogMissedFilesURL.CreateFile(cLogFileName);
  end;
  //
  // Create log files for files with errors (filesize, md5, crc32, etc)
  //
  if Settings.LogCreateErrorFileSize then begin
    FLogErrorFileSize := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileErrorFileSize, Settings.AppDir);
    FLogErrorFileSize.CreateFile(cLogFileName);
  end;
  //
  if Settings.LogCreateErrorMD5 then begin
    FLogErrorMD5 := TfmLogFile.Create(nil);
    cLogFileName :=
      GetAbsoluteFileName(Settings.LogFileErrorMD5, Settings.AppDir);
    FLogErrorMD5.CreateFile(cLogFileName);
  end;
end;
//
procedure TfrmMain.edtCheckFinishIDChange(Sender: TObject);
begin
  Settings.CheckFinishID := StrToIntDef(edtCheckFinishID.Text, 0);
end;
//
procedure TfrmMain.edtCheckStartIDChange(Sender: TObject);
begin
  Settings.CheckStartID := StrToIntDef(edtCheckStartID.Text, 0);
end;

procedure TfrmMain.edtGenesisCSVFileChange(Sender: TObject);
begin
end;

//
procedure TfrmMain.Exit1Click(Sender: TObject);
begin
  Close;
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.Destroy
//   Free memory and destroy exemplars of objects, used by application
// Parameters:
//   None
// Result:
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  //
  // Save table to dump, if correspondig flag is set
  //
  if Settings.AutoSaveLocalDBDump then
    FGenesisLocal.SaveDataToDump(Settings.LocalDBDumpFile);
  //
  // Save application settings, destroy exemplar of TAppSettings class
  //
  SaveAppSettings;
  Settings.SaveSettings;
  FreeAppSettings;
  //
  // Free memory used by stringlists
  //
//  SetLength(FGenesisFilename,0);
//  SetLength(FGenesisID,0);
//  SetLength(FGenesisFileSize,0);
//  SetLength(FGenesisMD5,0);
  //
  // Free memory and destroy exemplar of TGenesisLocalRepository class
  //
  FreeAndNil(FGenesisLocal);
  FreeAndNil(FCSVFile);
  FProcessedFilesList.Clear;
  FreeAndNil(FProcessedFilesList);
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.Create
//   Initialize main application form internal variables,
//     create exemplars of used classes 
// Parameters:
//   None
// Result:
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  //
  // Create exemplar of TGenesisLocalRepository class
  //
  frmSplash.lblState.Caption := rstrInitializationMessage;
  Application.ProcessMessages;
  FGenesisLocal := TGenesisLocalRepository.Create;
  FCSVFile := TCSVFile.Create();
  //
  FProcessedFilesList := TStringList.Create;
  FProcessedFilesList.Clear;
  FProcessedFilesList.Sorted := True;
  FProcessedFilesList.Duplicates := dupIgnore;
  //
  // Create exemplar of TAppSettings class, load application settings
  //
  frmSplash.lblState.Caption := rstrLoadSettings;
  Application.ProcessMessages;
  FInitialized := False;
  LoadAppSettings;
  FInitialized := True;
  //
  // initialize Repositories settings
  //
  LoadRepositoriesData(FGenesisLocal);
  //
  // Load table from dump, if correspondig flag is set
  //
  if Settings.AutoLoadLocalDBDump then begin
    frmSplash.lblState.Caption := rstrLoadDatabase;
    Application.ProcessMessages;
    FGenesisLocal.LoadDataFromDump(Settings.LocalDBDumpFile);
  end;
  //
  // Set visual controls states
  //
  SetControlStates;
  frmSplash.Hide;
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.FreeLogFiles
//   Release resoources allocated to log files' variables
// Parameters:
// -
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.FreeLogFiles;
begin
  FreeAndNil(FLogExistFiles);
  FreeAndNil(FLogMissedFiles);
  FreeAndNil(FLogErrorFileSize);
  FreeAndNil(FLogErrorMD5);
  FreeAndNil(FLogMissedFilesURL);
  //
  FreeAndNil(FLogOutdatedFiles);
  FreeAndNil(FLogExtraFiles);
  FreeAndNil(FLogErrorID);
end;
//------------------------------------------------------------------------------
// function TfrmMain.GetLocalRepositoryDir
//   Returns local repository root directory for input GenesisID
// Parameters:
//   const GenesisID: integer - input GenesisID value
// Result: AnsiString
//   Returns local repository root directory for input GenesisID
//------------------------------------------------------------------------------
function TfrmMain.GetLocalRepositoryDir(const GenesisID: Integer): AnsiString;
var
  nRepIndex: Integer;
begin
  Result := '';
  //
  // Search first repository, where (MinID <= GenesisID) and (GenesisID <= MaxID)
  //
  for nRepIndex := 0 to Settings.RepositoriesCount - 1 do begin
    if (Settings.Repositories[nRepIndex].MinID <= GenesisID) and
      (GenesisID <= Settings.Repositories[nRepIndex].MaxID) then
    begin
      Result :=
        IncludeTrailingPathDelimiter(Settings.Repositories[nRepIndex].BaseDir);
      Break;  // for nRepIndex := 0 ...
    end;
  end;
end;
//------------------------------------------------------------------------------
// function TfrmMain.GetGenesisFileURL
//   Returns URL of selected web file
// Parameters:
//   const GenesisFile: integer - index of file in internal file properties arrays
// Result: AnsiString
//   download URL of specified file, or '' if error occured
//------------------------------------------------------------------------------
function TfrmMain.GetGenesisFileURL(const GenesisFile: TGenesisRecord):
    AnsiString;
var
  cGenesisFileURL: AnsiString;
  cTemplateValue: AnsiString;
begin
  Result := '';
  //
  cGenesisFileURL := GetServerTemplateURL(GenesisFile.ID);
  //
  // Replace templates with variables values
  //
  if Pos(MD5_TEMPLATE, cGenesisFileURL) <> -1 then begin
    cTemplateValue := GenesisFile.MD5;
    cGenesisFileURL := ReplaceStr(cGenesisFileURL, MD5_TEMPLATE, cTemplateValue);
  end;
  //
  if Pos(REPOSITORY_SUBDIR_TEMPLATE, cGenesisFileURL) <> -1 then begin
    cTemplateValue :=
      ExcludeTrailingPathDelimiter(ExtractFilePath(GenesisFile.FileName));
    cGenesisFileURL :=
      ReplaceStr(cGenesisFileURL, REPOSITORY_SUBDIR_TEMPLATE, cTemplateValue);
  end;
  Result := cGenesisFileURL;
end;
//------------------------------------------------------------------------------
// function TfrmMain.GetServerTemplateURL
//   Returns template URL of genesis file
// Parameters:
//   const GenesisID: Integer - ID of file in genesis database
// Result: AnsiString
//   Returns template URL of genesis file (with {MD5}, {RelativeDir} variables),
//   or empty string, if error occured
//------------------------------------------------------------------------------
function TfrmMain.GetServerTemplateURL(const GenesisID: Integer): AnsiString;
var
  nSrvIndex: integer;
begin
  Result := '';
  //
  // Search first server, containing file with specified GenesisID.
  //
  for nSrvIndex := 0 to Settings.ServersCount - 1 do begin
    if (Settings.Servers[nSrvIndex].MinID <= GenesisID) and
      (GenesisID <= Settings.Servers[nSrvIndex].MaxID) then
    begin
      Result := Settings.Servers[nSrvIndex].TemplateURL;
      Break;
    end;
  end;
end;
//------------------------------------------------------------------------------
// function TfrmMain.GetStartFileIndex
//   Returns FileIndex corresponding to specified GenesisID
// Parameters:
//   const GenesisID: integer - Genesis id value
// Result: integer
//   FileIndex corresponding to GenesisID
//------------------------------------------------------------------------------
function TfrmMain.GetStartFileIndex(const GenesisID: Integer): Integer;
var
  nLowIndex: integer;
  nMiddleIndex: integer;
  nHighIndex: integer;
  nDelta: Integer;
begin
  Result := 0;
  //
  nLowIndex := 0;
  nHighIndex := FGenesisLocal.TotalFilesCount;
  repeat
    nMiddleIndex := (nLowIndex + nHighIndex) div 2;

    if FGenesisLocal.Files[nMiddleIndex].ID < GenesisID then begin
      nLowIndex := nMiddleIndex;
    end;
    if GenesisID < FGenesisLocal.Files[nMiddleIndex].ID then begin
      nHighIndex := nMiddleIndex;
    end;

    nDelta := nHighIndex - nLowIndex;
  until (FGenesisLocal.Files[nMiddleIndex].ID = GenesisID) or (nDelta = 1);
  //
  if (FGenesisLocal.Files[nMiddleIndex].ID <> GenesisID) then begin
    if FGenesisLocal.Files[nLowIndex].ID = GenesisID then
      nMiddleIndex := nLowIndex;
    if FGenesisLocal.Files[nHighIndex].ID = GenesisID then
      nMiddleIndex := nHighIndex;
  end;
  //
  Result := nMiddleIndex;
end;

procedure TfrmMain.jvtrtl1RepaintRequest(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.jvtrtl1RepaintRequest default body inserted
end;

//------------------------------------------------------------------------------
// procedure TfrmMain.LoadAppLocalDBSettings
//   Initialize visual controls according to application check settings
// Parameters:
// - 
// Result: Boolean
//------------------------------------------------------------------------------
procedure TfrmMain.LoadAppCheckSettings;
begin
  chkCheckMissedFiles.Checked := Settings.ProcessLocalFiles;
  chkCheckExtraFiles.Checked := Settings.ProcessExtraFiles;
  //
  edtCheckStartID.Text := IntToStr(Settings.CheckStartID);
  edtCheckFinishID.Text := IntToStr(Settings.CheckFinishID);
  //
  chkCheckFileSize.Checked := cstFileSize in Settings.LocalFilesChecks;
  chkCheckMD5Hash.Checked := cstMD5 in Settings.LocalFilesChecks;
  chkCheckCRC32.Checked := cstCRC32 in Settings.LocalFilesChecks;
end;
//
procedure TfrmMain.LoadAppLocalDBSettings;
begin
  //
  edtGenesisCSVFile.Text := Settings.GenesisCSVFile;

  // TODO -cMM: TfrmMain.LoadAppLocalDBSettings default body inserted
end;

//------------------------------------------------------------------------------
// procedure TfrmMain.LoadAppSettings
//   Initialize visual controls according to application log files settings 
// Parameters:
// - 
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.LoadAppLogSettings;
begin
//
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.LoadAppSettings
//   Load application parameters and initialize visual controls
// Parameters:
//   None
// Result:
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.LoadAppSettings;
begin
  //
  LoadAppLocalDBSettings;
  //
  LoadAppCheckSettings;
  //
  LoadAppLogSettings;
end;
//------------------------------------------------------------------------------
// function TfrmMain.LoadGenesisData
//   Load genesis repository and filelist data into FGenesisLocal variable
// Parameters:
//   const GenesisFileList: AnsiString - input data file location
// Result: Boolean
//   True, if import was successful; False, if error occured.
//------------------------------------------------------------------------------
function TfrmMain.LoadGenesisData(const GenesisFileList: AnsiString): Boolean;
var
  nIndex: integer;
begin
  Result := False;
  //
  // Load local genesis repository information
  //
  FGenesisLocal.ClearRepositories;
  for nIndex := 0 to Settings.RepositoriesCount - 1 do
    FGenesisLocal.AddRepository(Settings.Repositories[nIndex]);
  //
  // Load genesis files information
  //
  FGenesisLocal.LoadDataFromCSV(GenesisFileList);
  Result := True;
end;
//------------------------------------------------------------------------------
// function TfrmMain.LoadGenesisFileList
//   Load genesis current filelist into internal stringlist
// Parameters:
//   const FileName: AnsiString - fullname of filelist file
// Result:
//   None
//------------------------------------------------------------------------------
function TfrmMain.LoadGenesisFileList(const FileName: AnsiString): Boolean;
begin
  Result := False;
  { TODO -oAdministrator -c :  Realize clear routine for FGenesisLocal
    03.04.2010 19:19:26 }
  //
  // Initialize local repository variable and clear current data
  //
  FGenesisLocal.ClearRepositories;
  FGenesisLocal.ClearGenesisFiles;
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.LoadRepositoriesData
//   Load repositories data from settings to specified local repository
// Parameters:
//   var LocalRepository : TGenesisLocalRepository  - specified local repository
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.LoadRepositoriesData(
    var LocalRepository: TGenesisLocalRepository);
var
  i: Integer;
begin
  LocalRepository.ClearRepositories;
  for I := 0 to Settings.RepositoriesCount - 1 do begin
    LocalRepository.AddRepository(Settings.Repositories[i]);
  end;
end;
//------------------------------------------------------------------------------
// function TfrmMain.ParseRecord
//   Parse input record with specified delimiter and store data into output
//   stringlist. Output stringlist must exists.
// Parameters:
//   const InputString: AnsiString - input string for analize
//   const FieldDelimiter: AnsiChar - record fields' delimiter
//   const UnQuoteStr: Boolean - unquote result fields
//   var SL:TStringList - output stringlist for store results
// Result: Integer
//   Count of fields in input record
//------------------------------------------------------------------------------
function TfrmMain.ParseRecord(const InputString: AnsiString; const
    FieldDelimiter: AnsiChar; const UnQuoteStr: Boolean; var SL: TStringList): Integer;
var
  nCharIndex: integer;
  cCurrField: AnsiString;
begin
  Result := 0;
  //
  // Initialize variables. Clear output stringlist, for case of empty input string
  //
  SL.Clear;
  //
  // For AnsiString, chars' indices start from 1.
  //   Process input string 'char by char'
  //
  cCurrField := '';
  for nCharIndex := 1 to Length(InputString) do begin
    //
    // If current char is field delimiter, add field value to output stringlist,
    //   otherwise add char to temporary field variable
    //
    if InputString[nCharIndex] = FieldDelimiter then begin
      if UnQuoteStr then
        cCurrField := AnsiDequotedStr(cCurrField, '"');
      SL.Add(cCurrField);
      cCurrField := '';
    end
    else begin
      cCurrField := cCurrField + InputString[nCharIndex];
    end;
  end;
  //
  // if temporary field variable not empty or last string char is field delimiter,
  //   add field value to output stringlist
  //
  if (cCurrField <> '') or (InputString[Length(InputString)] = FieldDelimiter) then
  begin
    if UnQuoteStr then
      cCurrField := AnsiDequotedStr(cCurrField, '"');
    SL.Add(cCurrField);
  end;
  //
  // Set output result and exit function
  //
  Result := SL.Count;
end;

procedure TfrmMain.pgc1Change(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.pgc1Change default body inserted
end;

procedure TfrmMain.pgcTasksChange(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.pgcTasksChange default body inserted
end;

procedure TfrmMain.pnlTabCaptionClick(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.pnlTabCaptionClick default body inserted
end;

procedure TfrmMain.pnlTabSelectorClick(Sender: TObject);
begin
  // TODO -cMM: TfrmMain.pnlTabSelectorClick default body inserted
end;

//------------------------------------------------------------------------------
// procedure TfrmMain.SaveAppCheckSettings
//   Set application settings related to local repository checks
// Parameters:
// -
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.SaveAppCheckSettings;
var
  xLocalFilesChecks: TCheckState;
begin
  //
  // Set id range settings, local repository and extra files processing flags
  //
  Settings.ProcessLocalFiles := chkCheckMissedFiles.Checked;
  Settings.ProcessExtraFiles := chkCheckExtraFiles.Checked;
  Settings.CheckStartID := StrToIntDef(edtCheckStartID.Text, 0);
  Settings.CheckFinishID := StrToIntDef(edtCheckFinishID.Text,0);
  //
  // Assign local repository files check state to corresponding settings
  //
  xLocalFilesChecks := [cstFileName];   // alwais check filename
  if chkCheckFileSize.Checked then
    xLocalFilesChecks := xLocalFilesChecks + [cstFileSize];
  if chkCheckMD5Hash.Checked then
    xLocalFilesChecks := xLocalFilesChecks + [cstMD5];
  if chkCheckCRC32.Checked then
    xLocalFilesChecks := xLocalFilesChecks + [cstCRC32];
  Settings.LocalFilesChecks := xLocalFilesChecks;
end;

procedure TfrmMain.SaveAppLocalDBSettings;
begin
  // TODO -cMM: TfrmMain.SaveAppLocalDBSettings default body inserted
end;

procedure TfrmMain.SaveAppLogSettings;
begin
  // TODO -cMM: TfrmMain.SaveAppLogSettings default body inserted
end;

//------------------------------------------------------------------------------
// procedure TfrmMain.SaveAppSettings
//   Save application parameters into ini-file
// Parameters:
//   None
// Result:
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.SaveAppSettings;
begin
  //
  SaveAppLocalDBSettings;
  //
  SaveAppCheckSettings;
  //
  SaveAppLogSettings;
end;
//------------------------------------------------------------------------------
// Procedure TfrmMain.SetControlStates
//   Set controls' states depend of flag variables
// Parameters:
//   None
// Result:
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.SetControlStates;
//var
//  bNotLocked: Boolean;
begin
  //
  // Set components' states only after settings is loaded
  //
  if not FInitialized then
    Exit;
  //
  // Initialize information panels
  //
  pnlTabCaption.Caption := pgcTasks.ActivePage.Caption;
  if FProcessing then
    Screen.Cursor := crHourGlass
  else
    Screen.Cursor := crDefault;
  //
  // Set control panels elements states
  //
  SetLocalDBTabControlsState;
  SetCheckRepositoryFilesTabControlsState;
  //
  //


end;

//------------------------------------------------------------------------------
// procedure TfrmMain.SetControlState
//   Set all controls state dessendents Active property to False;
// Parameters:
//    Control : TWinControl  - 
// Result: None
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.SetControlState(Control: TWinControl; const State: Boolean);
var
  nIndex: Integer;
  SubControl: TWinControl;
begin
  with Control do begin
    for nIndex := 0 to Control.ControlCount - 1 do begin
      if (Control.Controls[nIndex] is TWinControl) then begin
        SubControl := Control.Controls[nIndex] as TWinControl;
        if SubControl.ControlCount > 0 then
          SetControlState(SubControl, State);
        SubControl.Enabled := State;
      end;
    end;
    Control.Enabled := State;
  end;
end;
//------------------------------------------------------------------------------
// TfrmMain.SetLocalDBTabControlsState
//   INternal to procedure SetControlStates only.
//     Set state of controls of tab 'Local DB'
// Parameters:
// -
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.SetLocalDBTabControlsState;
const
  DB_OPENED_CAPTION = 'DB is opened';
  DB_CLOSED_CAPTION = 'DB is closed';
  TABLE_SHOW_CAPTION = 'Data is showed';
  TABLE_HIDE_CAPTION = 'Data is hided';
begin
  tabDatabase.Enabled := not FProcessing;
  SetControlState(tabDatabase, not FProcessing);
  if not FProcessing then begin
    //
    // Set active states for genesis csv file related properties
    //
    edtGenesisCSVFile.Text := Settings.GenesisCSVFile;
    edtGenesisCSVFile.Enabled := not FGenesisLocal.TableActive;
    btnCreateDBfromCSV.Enabled := (not FGenesisLocal.TableActive) and
      FileExists(edtGenesisCSVFile.Text);
    btnSelectCSVFile.Enabled := not FGenesisLocal.TableActive;
    //
    // Set active states for genesis csv file related properties
    //
    edtLocalDBDumpFile.Text := Settings.LocalDBDumpFile;
    edtLocalDBDumpFile.Enabled := not FGenesisLocal.TableActive;
    btnSelectLocalDBDumpFile.Enabled := not FGenesisLocal.TableActive;
    //
    btnLoadLocalDBFromDump.Enabled := (not FGenesisLocal.TableActive) and
      FileExists(edtLocalDBDumpFile.Text);
    btnSaveDBToDump.Enabled := FGenesisLocal.TableActive;
    //
    // Set local db state label information and save|load dump flags
    //
    chkAutoSaveDBDump.Checked := Settings.AutoSaveLocalDBDump;
    chkAutoLoadDBDump.Checked := Settings.AutoLoadLocalDBDump;
    //
    // Set open/close db and show/hide table controls state
    //
    btnOpenCloseDB.Enabled := FGenesisLocal.DataLoaded;
    if FGenesisLocal.TableActive then
      lblDBState.Caption := DB_OPENED_CAPTION
    else
      lblDBState.Caption := DB_CLOSED_CAPTION;
    btnShowTable.Enabled := FGenesisLocal.TableActive;
    if FGenesisLocal.DataSource.Enabled then
      lblTableViewState.Caption := TABLE_SHOW_CAPTION
    else
      lblTableViewState.Caption := TABLE_HIDE_CAPTION;
  end;
end;

procedure TfrmMain.SetCheckRepositoryFilesTabControlsState;
var
  bNotLocked: Boolean;
begin
  //
  // Set entire tab controls state
  //
  bNotLocked := (not FProcessing) and FGenesisLocal.TableActive;
  SetControlState(tabCheckRepositoryFiles, bNotLocked);
  if not bNotLocked then begin
    Exit;
  end;
  //
  // Set state of data and flag fields
  //
  chkCheckMD5Hash.Checked := cstMD5 in Settings.LocalFilesChecks;
  chkCheckFileSize.Checked := cstFileSize in Settings.LocalFilesChecks;
  //
  edtCheckStartID.Enabled := bNotLocked;
  edtCheckFinishID.Enabled := bNotLocked;
  //
  // Set state of command controls
  //
  btnAnalizeRepository.Enabled := bNotLocked;
end;

//------------------------------------------------------------------------------
// TfrmMain.Settings1Click
//    Show application settings dialog (in modal mode)
// Parameters:
//    Sender : TObject  - pointer to Main form
// Result:
//    None
//------------------------------------------------------------------------------
procedure TfrmMain.Settings1Click(Sender: TObject);
begin
  frmSettings.ShowModal;
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.ShowProgressStatistics
//   Show progress statistics of repository check operation
// Parameters:
//   const Visible: Boolean - define if statistics is visible
// Result:
//   None
//------------------------------------------------------------------------------
procedure TfrmMain.ShowProgressStatistics(const Visible: Boolean);
begin
  if Visible = True then begin
    edtGenesisID.Text := IntToStr(FCurrentGenesisID);
    { TODO -oMichel -c :  Add processing of TotalFilesCount variable 18.11.2010 18:57:13 }
    edtFilesProcessedStat.Text := IntToStr(FGenesisLocal.TotalFilesCount);
    edtFilesProcessedStat.Text := IntToStr(FGenesisProcessedFiles);
    edtFileFoundStat.Text := IntToStr(FGenesisExistFilesCount);
    edtFilesMissedStat.Text := IntToStr(FGenesisMissedFilesCount);
    edtExtraFilesStat.Text := IntToStr(FGenesisExtraFilesCount);
    edtFileSizeErrorStat.Text := IntToStr(FGenesisFileSizeErrorCount);
    edtMD5ErrorStat.Text := IntToStr(FGenesisMD5ErrorCount);
    edtCRC32ErrorStat.Text := IntToStr(FGenesisCRC32ErrorCount);
  end
  else begin
    edtGenesisID.Text := '';
    edtFilesProcessedStat.Text := '';
    edtFilesProcessedStat.Text := '';
    edtFileFoundStat.Text := '';
    edtFilesMissedStat.Text := '';
    edtExtraFilesStat.Text := '';

  end;
  Application.ProcessMessages;
end;
//------------------------------------------------------------------------------
// procedure TfrmMain.udCheckFinishIDChangingEx
//   Change value in edtCheckFinishID by 1000 (decrease or increase depending
//      from selected change direction)
// Parameters:
//    Sender : TObject              - not used
//    var AllowChange : Boolean     - not used
//    NewValue : SmallInt           - not used
//    Direction : TUpDownDirection  - change direction: updUp or updDown
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.udCheckFinishIDChangingEx(Sender: TObject; var AllowChange:
    Boolean; NewValue: SmallInt; Direction: TUpDownDirection);
var
  nValue: Integer;
  nThousandsCount: Integer;
begin
  //
  // Get genesis id digital value, define thousands count
  //
  nValue := StrToIntDef(edtCheckFinishID.Text, 0);
  nThousandsCount := nValue div 1000;
  //
  // add or delete one thousand from value; set last numbers to '999'
  //
  case Direction of
    updUp:
      nValue := (nThousandsCount + 2)*1000 - 1;
    updDown:
      nValue := (nThousandsCount * 1000) - 1;
    updNone:
      udCheckFinishID.Position :=
        (udCheckFinishID.Min + udCheckFinishID.Max) div 2;
  end;
  //
  // If value is negative, assign to it value 999
  //
  if nValue < 0 then
    nValue := 1000 - 1;
  //
  // Assign text to assosiated text input field and call OnChange function
  //
  edtCheckFinishID.Text := IntToStr(nValue);
  edtCheckFinishIDChange(nil);
end;

//------------------------------------------------------------------------------
// procedure TfrmMain.udCheckStartIDChangingEx
//   Change value in edtCheckStartID by 1000 (decrease or increase depending
//      from selected change direction)
// Parameters:
//    Sender : TObject              - not used
//    var AllowChange : Boolean     - not used
//    NewValue : SmallInt           - not used
//    Direction : TUpDownDirection  - change direction: updUp or updDown
// Result: None
//------------------------------------------------------------------------------
procedure TfrmMain.udCheckStartIDChangingEx(Sender: TObject; var AllowChange:
    Boolean; NewValue: SmallInt; Direction: TUpDownDirection);
var
  nValue: Integer;
  nThousandsCount: Integer;
begin
  //
  // Get genesis id digital value, define thousands count
  //
  nValue := StrToIntDef(edtCheckStartID.Text, 0);
  nThousandsCount := nValue div 1000;
  //
  // add or delete one thousand from value; set last numbers to '999'
  //
  case Direction of
    updUp:
      nValue := (nThousandsCount + 1) * 1000;
    updDown:
      nValue := (nThousandsCount - 1) * 1000;
    updNone:
      udCheckStartID.Position :=
        (udCheckStartID.Min + udCheckStartID.Max) div 2;
  end;
  //
  // If value is negative, assign to it value 999
  //
  if nValue < 0 then
    nValue := 0;
  //
  // Assign text to assosiated text input field and call OnChange function
  //
  edtCheckStartID.Text := IntToStr(nValue);
  edtCheckStartIDChange(nil);
end;
//------------------------------------------------------------------------------
// function TfrmMain.UpdateLogFiles
//   Add record to log files, if specified conditions is correct
// Parameters:
//   const FileState : TFileState - file state of processed file
//   const FileID : Integer  - genesis id of processed file
// Result: Boolean
//   True, if log's update is successful; False otherwise
//------------------------------------------------------------------------------
function TfrmMain.UpdateLogFiles(const FileState: TFileState; const GenesisFile:
    TGenesisRecord): Boolean;
var
  cLogMessage: AnsiString;
  bFileMatch: Boolean;
  bLogProcessed: Boolean;
begin
  Result := False;
  cLogMessage := EmptyStr;
  //
  // Log data to bad id log file
  //
  try
    //
    // Process logs for error states
    //
    Inc(FGenesisProcessedFiles);
    bLogProcessed := False;
    if (fstBadId in FileState) then begin
      //
      // Update bad id range file's filelist
      //
      cLogMessage := IntToStr(GenesisFile.ID);
      FLogErrorID.WriteToLog(cLogMessage);
      Inc(FCheckErrorsCount);
      //
      // id is uncorrect, don't need to process other log files - exit function
      //
      bLogProcessed := True;
      Result := True;
    end;
    //
    if (fstOutOfRepIdRange in FileState) then begin
      //
      // Update bad repository range file's filelist
      //
      cLogMessage := IntToStr(GenesisFile.ID);
      FLogRepositoryNotSet.WriteToLog(cLogMessage);
      Inc(FCheckErrorsCount);
      //
      // repository for  specified id not set,
      //   don't need to process other log files - exit function
      //
      bLogProcessed := True;
      Result := True;
    end;
    //
    // Log data to missed files
    //
    if not (fstFileExists in FileState) then begin
      bFileMatch := False;
      //
      // Add file to missed file's filelist
      //
      if Settings.LogCreateMissedFiles and (not bLogProcessed) then
      begin
        cLogMessage := GenesisFile.FileName;
        FLogMissedFiles.WriteToLog(cLogMessage);
      end;
      if not (fstBadID in FileState) then
        Inc(FGenesisMissedFilesCount);
    end
    else begin
      bFileMatch := False;
      //
      // Log data for outdated files
      //
      if (fstOutdatedFile in FileState) then begin
        cLogMessage := IntToStr(GenesisFile.ID);
        FLogOutdatedFiles.WriteToLog(cLogMessage);
        Inc(FGenesisOutdatedFilesCount);
        //
        bLogProcessed := True;
        Result := True;
      end;
      //
      // Log data for extra files
      //
      if fstExtraFile in FileState then begin
        cLogMessage := GenesisFile.FullName; // MUST contain absolute path to file
        FLogExtraFiles.WriteToLog(cLogMessage);
        Inc(FGenesisExtraFilesCount);
        //
        bLogProcessed := True;
        Result := True;
      end;
      //
      // Check filesize condition
      //
      if not bLogProcessed then begin
        bFileMatch := True;
        if (cstFileSize in Settings.LocalFilesChecks) then begin
          if not (fstFileSize in FileState) then begin
            bFileMatch := False;
            Inc(FGenesisFileSizeErrorCount);
            cLogMessage := GenesisFile.FileName;
            FLogErrorFileSize.WriteToLog(cLogMessage);
          end;
        end;
        //
        // Check md5 condition
        //
        if (cstMD5 in Settings.LocalFilesChecks) then begin
          if not (fstMD5 in FileState) then begin
            bFileMatch := False;
            Inc(FGenesisMD5ErrorCount);
            cLogMessage := GenesisFile.FileName;
            FLogErrorMD5.WriteToLog(cLogMessage);
          end;
        end;
        //
        // Check crc32 condition
        //
        if (cstCRC32 in Settings.LocalFilesChecks) then begin
          if not (fstCRC32 in FileState) then begin
            bFileMatch := False;
            Inc(FGenesisCRC32ErrorCount);
            cLogMessage := GenesisFile.FileName;
    //        FLogErrorMD5.WriteToLog(cLogMessage);
          end;
        end;
        //
        // Add file to exist file's filelist
        //
        cLogMessage := GenesisFile.FileName;
        FLogExistFiles.WriteToLog(cLogMessage);
        if (bFileMatch = True) then begin
          Inc(FGenesisExistFilesCount);
        end
        else begin
          if not (fstBadID in FileState) then
            Inc(FGenesisMissedFilesCount);
        end;
      end;
    end;
    //
    // if flag specified, generate download file links
    //
    if (not bFileMatch) and (not (fstBadID in FileState)) and
        (Settings.LogCreateMissedFilesURL = True) then
    begin
      cLogMessage := GetGenesisFileURL(GenesisFile);
      if cLogMessage <> '' then begin
        //
        // Add file to missed file URL's filelist
        //
        FLogMissedFilesURL.WriteToLog(cLogMessage);
      end;
    end;
    Result := True;
  finally
  end;
end;

end.
